package com.speedchina.common.upload.utils;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.converters.AutoConverter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.metadata.CellData;

import com.speedchina.common.upload.annotation.Unique;
import com.speedchina.common.upload.response.Result;
import org.apache.commons.lang3.ArrayUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

public class MapUtil {

    /**
     * map转对象
     * 成功
     * {
     *     data:成功list
     *     size:成功条数
     *     code:true
     * }
     * or
     * 失败
     * {
     *     data:失败list警告
     *     size:失败条数
     *     code:false
     * }
     * @param maps      读取的对象
     * @param clazz     需要转换的对象
     * @param headerRow 表头行 第一行是 1
     * @author suyuan
     * @date 2021/5/28 14:16
     */
    public static <T> Result map2Object(List<Map<String, Object>> maps, Class<T> clazz,int headerRow) throws Exception {
        // DO: 2021/5/28 封装一个消息返回成功或者错误信息
        Result result = new Result();
        ArrayList<T> listsuccess = new ArrayList<T>();
        ArrayList<String> listfail = new ArrayList<>();
        Map<Object, Integer> m=new HashMap<>();
        int i=headerRow;
        for(Map<String, Object> map : maps){
            i++;
            T t = clazz.newInstance();
            // DO: 2021/5/28 下划线转驼峰
            Iterator<Map.Entry<String, Object>> entries = map.entrySet().iterator();
            while (entries.hasNext()) {
                Map.Entry<String, Object> entry = entries.next();
                Object fieldValue = entry.getValue();
                // TODO: 2021/6/4 字典转换转换的不对要不要提醒？
                Field newField = ReflectUtil.getField(clazz, StrUtil.toCamelCase(entry.getKey()));
                if (newField != null) {
                    newField.setAccessible(true);
                    if (newField.isAnnotationPresent(ExcelProperty.class)) {
                        Class<? extends Converter> converter1 = newField.getAnnotation(ExcelProperty.class).converter();
                        if(!converter1.equals(AutoConverter.class)){
                            Converter converter = newField.getAnnotation(ExcelProperty.class).converter().newInstance();
                            CellData cellData = new CellData( converter.convertToJavaData(new CellData(fieldValue) , null, null));
                            if (cellData.getData() != null) {
                                fieldValue = cellData.getData();
                            }
                        }
                    }
                    Class<?> fieldType = newField.getType();
                    if (fieldType.equals(String.class) && String.valueOf(fieldValue).contains(".0")) {
                        fieldValue = convertRate2Decimal(fieldValue);
                    }
                    Object convert = Convert.convert(fieldType, fieldValue);
                    newField.set(t, Convert.convert(fieldType, fieldValue));
                    if (convert == null) {
                        listfail.add("第" + i + "行的" + entry.getKey() + "列数据类型有问题，请自行检查");
                    } else {
                        //唯一性校验
                        if (newField.isAnnotationPresent(Unique.class)) {
                            Integer count = m.get(convert);
                            m.put(convert, (count == null) ? 1 : count + 1);
                            if (m.get(convert) != null && m.get(convert) > 1) {
                                listfail.add("第" + i + "行的" + entry.getKey() + "列数据值有重复:" + convert + "，请自行检查");
                            }
                        }
                    }
                }
            }
            listsuccess.add(t);
        }
        if(listfail.size()!=0){
            result.setData(listfail);
            result.setSize(listfail.size());
            result.setCode(false);
        }
        else {
            result.setData(listsuccess);
            result.setSize(listsuccess.size());
            result.setCode(true);
        }
        return result;
    }


    public static String convertRate2Decimal(Object rate) {
        if (rate == null) {
            return null;
        }
        BigDecimal bd = Convert.toBigDecimal(rate);
        if (bd == null) {
            return Convert.toStr(rate);
        }
        return bd.stripTrailingZeros().toPlainString();
    }

    /**
     * Object转List
     * @author suyuan
     * @date 2021/6/8 9:32
     */
    public static <T> List<T> castList(Object obj, Class<T> clazz)
    {
        List<T> result = new ArrayList<T>();
        if(obj instanceof List<?>)
        {
            for (Object o : (List<?>) obj)
            {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }

}
